home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / SLAX 6.0.8 / slax-6.0.8.iso / slax / base / 006-devel.lzm / usr / include / KoXmlWriter.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-05-30  |  10.4 KB  |  282 lines

  1. /* This file is part of the KDE project
  2.    Copyright (C) 2004 David Faure <faure@kde.org>
  3.  
  4.    This library is free software; you can redistribute it and/or
  5.    modify it under the terms of the GNU Library General Public
  6.    License as published by the Free Software Foundation; either
  7.    version 2 of the License, or (at your option) any later version.
  8.  
  9.    This library is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.    Library General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU Library General Public License
  15.    along with this library; see the file COPYING.LIB.  If not, write to
  16.    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17.  * Boston, MA 02110-1301, USA.
  18. */
  19.  
  20. #ifndef XMLWRITER_H
  21. #define XMLWRITER_H
  22.  
  23. #include <qstring.h>
  24. #include <qvaluestack.h>
  25. #include <qmap.h>
  26. #include <koffice_export.h>
  27.  
  28. class QIODevice;
  29.  
  30. /**
  31.  * A class for writing out XML (to any QIODevice), with a special attention on performance.
  32.  * The XML is being written out along the way, which avoids requiring the entire
  33.  * document in memory (like QDom does), and avoids using QTextStream at all
  34.  * (which in Qt3 has major performance issues when converting to utf8).
  35.  */
  36. class KOSTORE_EXPORT KoXmlWriter
  37. {
  38. public:
  39.     /**
  40.      * Create a KoXmlWriter instance to write out an XML document into
  41.      * the given QIODevice.
  42.      */
  43.     KoXmlWriter( QIODevice* dev, int indentLevel = 0 );
  44.  
  45.     /// Destructor
  46.     ~KoXmlWriter();
  47.  
  48.     QIODevice *device() const { return m_dev; }
  49.  
  50.     /**
  51.      * Start the XML document.
  52.      * This writes out the \<?xml?\> tag with utf8 encoding, and the DOCTYPE.
  53.      * @param rootElemName the name of the root element, used in the DOCTYPE tag.
  54.      * @param publicId the public identifier, e.g. "-//OpenOffice.org//DTD OfficeDocument 1.0//EN"
  55.      * @param systemId the system identifier, e.g. "office.dtd" or a full URL to it.
  56.      */
  57.     void startDocument( const char* rootElemName, const char* publicId = 0, const char* systemId = 0 );
  58.  
  59.     /// Call this to terminate an XML document.
  60.     void endDocument();
  61.  
  62.     /**
  63.      * Start a new element, as a child of the current element.
  64.      * @param tagName the name of the tag. Warning: this string must
  65.      * remain alive until endElement, no copy is internally made.
  66.      * Usually tagName is a string constant so this is no problem anyway.
  67.      * @param indentInside if set to false, there will be no indentation inside
  68.      * this tag. This is useful for elements where whitespace matters.
  69.      */
  70.     void startElement( const char* tagName, bool indentInside = true );
  71.  
  72.     /**
  73.      * Overloaded version of addAttribute( const char*, const char* ),
  74.      * which is a bit slower because it needs to convert @p value to utf8 first.
  75.      */
  76.     inline void addAttribute( const char* attrName, const QString& value ) {
  77.         addAttribute( attrName, value.utf8() );
  78.     }
  79.     /**
  80.      * Add an attribute whose value is an integer
  81.      */
  82.     inline void addAttribute( const char* attrName, int value ) {
  83.         QCString str;
  84.         str.setNum( value );
  85.         addAttribute( attrName, str.data() );
  86.     }
  87.     /**
  88.      * Add an attribute whose value is an unsigned integer
  89.      */
  90.     inline void addAttribute( const char* attrName, uint value ) {
  91.         QCString str;
  92.         str.setNum( value );
  93.         addAttribute( attrName, str.data() );
  94.     }
  95.     /**
  96.      * Add an attribute whose value is a floating point number
  97.      * The number is written out with the highest possible precision
  98.      * (unlike QString::number and setNum, which default to 6 digits)
  99.      */
  100.     void addAttribute( const char* attrName, double value );
  101.     /**
  102.      * Add an attribute which represents a distance, measured in pt
  103.      * The number is written out with the highest possible precision
  104.      * (unlike QString::number and setNum, which default to 6 digits),
  105.      * and the unit name ("pt") is appended to it.
  106.      */
  107.     void addAttributePt( const char* attrName, double value );
  108.  
  109.     /// Overloaded version of the one taking a const char* argument, for convenience
  110.     inline void addAttribute( const char* attrName, const QCString& value ) {
  111.         addAttribute( attrName, value.data() );
  112.     }
  113.     /**
  114.      * Add an attribute to the current element.
  115.      */
  116.     void addAttribute( const char* attrName, const char* value );
  117.     /**
  118.      * Terminate the current element. After this you should start a new one (sibling),
  119.      * add a sibling text node, or close another one (end of siblings).
  120.      */
  121.     void endElement();
  122.     /**
  123.      * Overloaded version of addTextNode( const char* ),
  124.      * which is a bit slower because it needs to convert @p str to utf8 first.
  125.      */
  126.     inline void addTextNode( const QString& str ) {
  127.         addTextNode( str.utf8() );
  128.     }
  129.     /// Overloaded version of the one taking a const char* argument
  130.     inline void addTextNode( const QCString& cstr ) {
  131.         addTextNode( cstr.data() );
  132.     }
  133.     /**
  134.      * @brief Adds a text node as a child of the current element.
  135.      *
  136.      * This is appends the litteral content of @p str to the contents of the element.
  137.      * E.g. addTextNode( "foo" ) inside a \<p\> element gives \<p\>foo\</p\>,
  138.      * and startElement( "b" ); endElement( "b" ); addTextNode( "foo" ) gives \<p\>\<b/\>foo\</p\>
  139.      */
  140.     void addTextNode( const char* cstr );
  141.  
  142.     /**
  143.      * @brief Adds a processing instruction
  144.      *
  145.      * This writes a processing instruction, like <?foo bar blah?>, where foo
  146.      * is the target, and the rest is the data.
  147.      *
  148.      * Processing instructions are used in XML to keep processor-specific
  149.      * information in the text of the document.
  150.      */
  151.     void addProcessingInstruction( const char* cstr );
  152.  
  153.     /**
  154.      * This is quite a special-purpose method, not for everyday use.
  155.      * It adds a complete element (with its attributes and child elements)
  156.      * as a child of the current element. The string is supposed to be escaped
  157.      * for XML already, so it will usually come from another KoXmlWriter.
  158.      */
  159.     void addCompleteElement( const char* cstr );
  160.  
  161.     /**
  162.      * This is quite a special-purpose method, not for everyday use.
  163.      * It adds a complete element (with its attributes and child elements)
  164.      * as a child of the current element. The iodevice is supposed to be escaped
  165.      * for XML already, so it will usually come from another KoXmlWriter.
  166.      * This is usually used with KTempFile.
  167.      */
  168.     void addCompleteElement( QIODevice* dev );
  169.  
  170.     // #### Maybe we want to subclass KoXmlWriter for manifest files.
  171.     /**
  172.      * Special helper for writing "manifest" files
  173.      * This is equivalent to startElement/2*addAttribute/endElement
  174.      * This API will probably have to change (or not be used anymore)
  175.      * when we add support for encrypting/signing.
  176.      * @note OASIS-specific
  177.      */
  178.     void addManifestEntry( const QString& fullPath, const QString& mediaType );
  179.  
  180.     /**
  181.      * Special helper for writing config item into settings.xml
  182.      * @note OASIS-specific
  183.      */
  184.     void addConfigItem( const QString & configName, const QString& value );
  185.     /// @note OASIS-specific
  186.     void addConfigItem( const QString & configName, bool value );
  187.     /// @note OASIS-specific
  188.     void addConfigItem( const QString & configName, int value );
  189.     /// @note OASIS-specific
  190.     void addConfigItem( const QString & configName, double value );
  191.     /// @note OASIS-specific
  192.     void addConfigItem( const QString & configName, long value );
  193.     /// @note OASIS-specific
  194.     void addConfigItem( const QString & configName, short value );
  195.  
  196.     // TODO addConfigItem for datetime and base64Binary
  197.  
  198.     /**
  199.      * @brief Adds a text span as nodes of the current element.
  200.      *
  201.      * Unlike KoXmlWriter::addTextNode it handles tabulations, linebreaks,
  202.      * and multiple spaces by using the appropriate OASIS tags.
  203.      *
  204.      * @param text the text to write
  205.      *
  206.      * @note OASIS-specific
  207.      */
  208.     void addTextSpan( const QString& text );
  209.     /**
  210.      * Overloaded version of addTextSpan which takes an additional tabCache map.
  211.      * @param text the text to write
  212.      * @param tabCache optional map allowing to find a tab for a given character index
  213.      * @note OASIS-specific
  214.      */
  215.     void addTextSpan( const QString& text, const QMap<int, int>& tabCache );
  216.  
  217.     /**
  218.      * @return the current indentation level.
  219.      * Useful when creating a sub-KoXmlWriter (see addCompleteElement)
  220.      */
  221.     int indentLevel() const { return m_tags.size() + m_baseIndentLevel; }
  222.  
  223. private:
  224.     struct Tag {
  225.         Tag( const char* t = 0, bool ind = true )
  226.             : tagName( t ), hasChildren( false ), lastChildIsText( false ),
  227.               openingTagClosed( false ), indentInside( ind ) {}
  228.         const char* tagName;
  229.         bool hasChildren; ///< element or text children
  230.         bool lastChildIsText; ///< last child is a text node
  231.         bool openingTagClosed; ///< true once the '\>' in \<tag a="b"\> is written out
  232.         bool indentInside; ///< whether to indent the contents of this tag
  233.     };
  234.  
  235.     /// Write out \n followed by the number of spaces required.
  236.     void writeIndent();
  237.  
  238.     // writeCString is much faster than writeString.
  239.     // Try to use it as much as possible, especially with constants.
  240.     void writeString( const QString& str );
  241.  
  242.     // unused and possibly incorrect if length != size
  243.     //inline void writeCString( const QCString& cstr ) {
  244.     //    m_dev->writeBlock( cstr.data(), cstr.size() - 1 );
  245.     //}
  246.  
  247.     inline void writeCString( const char* cstr ) {
  248.         m_dev->writeBlock( cstr, qstrlen( cstr ) );
  249.     }
  250.     inline void writeChar( char c ) {
  251.         m_dev->putch( c );
  252.     }
  253.     inline void closeStartElement( Tag& tag ) {
  254.         if ( !tag.openingTagClosed ) {
  255.             tag.openingTagClosed = true;
  256.             writeChar( '>' );
  257.         }
  258.     }
  259.     char* escapeForXML( const char* source, int length ) const;
  260.     bool prepareForChild();
  261.     void prepareForTextNode();
  262.     void init();
  263.  
  264.     QIODevice* m_dev;
  265.     QValueStack<Tag> m_tags;
  266.     int m_baseIndentLevel;
  267.  
  268.     class Private;
  269.     Private *d;
  270.  
  271.     char* m_indentBuffer; // maybe make it static, but then it needs a KStaticDeleter,
  272.                           // and would eat 1K all the time... Maybe refcount it :)
  273.     char* m_escapeBuffer; // can't really be static if we want to be thread-safe
  274.     static const int s_escapeBufferLen = 10000;
  275.  
  276.     KoXmlWriter( const KoXmlWriter & ); // forbidden
  277.     KoXmlWriter& operator=( const KoXmlWriter & ); // forbidden
  278. };
  279.  
  280. #endif /* XMLWRITER_H */
  281.  
  282.